/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package br.com.sintatico.programa;

import br.com.chain.presenter.TelaPrincipalPresenter;
import br.com.model.Token;
import java.util.ArrayList;
import javax.swing.ImageIcon;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.LookAndFeel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;

/**
 *
 * @author mariorsjr
 */
public class Sintatico {

    private int pos = 0;
    DefaultMutableTreeNode arvore;
    DefaultTreeModel model;
    private JTree raiz;
    private ArrayList<DefaultMutableTreeNode> pilhaDeNos = new ArrayList<>();

    public Sintatico() {
        pos = 0;
        arvore = new DefaultMutableTreeNode("Pascal Ufes");
        model = new DefaultTreeModel(arvore);
    }

    public TreeNode getNode(String nome) {
        TreeNode no = new DefaultMutableTreeNode(nome);
        return arvore.getChildAfter(no);
    }

    public void loadArvoreSintatica() {

        DefaultMutableTreeNode no = new DefaultMutableTreeNode("Raiz");
        DefaultTreeModel model = new DefaultTreeModel(no);

        if (TelaPrincipalPresenter.getViewStatic().getJPanelArvore().getTabCount() > 1) {
            TelaPrincipalPresenter.getViewStatic().getJPanelArvore().removeTabAt(1);
        }

        LookAndFeel previousLF = UIManager.getLookAndFeel();
        try {
            UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
            raiz = new JTree(model);
            UIManager.setLookAndFeel(previousLF);
        } catch (IllegalAccessException | UnsupportedLookAndFeelException | InstantiationException | ClassNotFoundException e) {
        }

        raiz.putClientProperty("JTree.lineStyle", "Angled");

        // No raiz
        pilhaDeNos.add(no);

        JScrollPane scrollTree = new JScrollPane(raiz);
        scrollTree.setViewportView(raiz);
        TelaPrincipalPresenter.getViewStatic().getJPanelArvore().add("Árvore de Análise Sintática", scrollTree);

        // Muda o ícone dos nós
        ImageIcon icon1 = new ImageIcon("src/br/com/view/no.png");
        DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer();
        renderer.setOpenIcon(icon1);
        renderer.setClosedIcon(icon1);
        renderer.setLeafIcon(icon1);
        raiz.setCellRenderer(renderer);

        // Exibe seta mostrando que há como contrair ou expandir um nó
        raiz.setShowsRootHandles(true);
    }

    private DefaultMutableTreeNode adicionarNo(DefaultMutableTreeNode pNo, String pNovoNo) {
        DefaultMutableTreeNode novo = new DefaultMutableTreeNode(pNovoNo);
        pNo.add(novo);
        pilhaDeNos.add(novo);
        return novo;
    }

    //-----------------------------------------------------------------------------------------------
    private void begin(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (tokens.get(pos).getToken().equals("Delimitador Inicio(begin)")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<begin>");
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pos++;
        } else {
            erros.add("Erro:É esperado begin:" + tokens.get(pos).getLinha());
        }
    }

    private void end(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (tokens.get(pos).getToken().equals("Delimitador Fim")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<end>");
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pos++;
        } else {
            erros.add("Erro:É esperado end:" + tokens.get(pos).getLinha());
        }
    }

    private void exprfechachaves(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (tokens.get(pos).getLexema().equals("]")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<exprFechaChaves>");
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pos++;
        } else {
            erros.add("Erro:É esperado um ]:" + tokens.get(pos).getLinha());
        }
    }

    private void exprdoispontosigual(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (tokens.get(pos).getToken().equals("Operador Atribuição Dois Pontos Igual")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<exprDoisPontosIgual>");
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pos++;
        } else {
            erros.add("Erro:É esperado um dois pontos igual:" + tokens.get(pos).getLinha());
        }
    }

    private void exprthen(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (tokens.get(pos).getToken().equals("Instrução Then")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<exprThen>");
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pos++;
        } else {
            erros.add("Erro:É esperado um then:" + tokens.get(pos).getLinha());
        }
    }

    private void exprdo(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (tokens.get(pos).getToken().equals("Instrução Do")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<exprDo>");
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pos++;
        } else {
            erros.add("Erro:É esperado um do:" + tokens.get(pos).getLinha());
        }
    }
    
     private void exprto(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (tokens.get(pos).getToken().equals("Instrução To")) {
            pos++;
        } else {
            erros.add("Erro:É esperado um to:" + tokens.get(pos).getLinha());
        }
    }

    private void expruntil(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (tokens.get(pos).getToken().equals("Instrução Until")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<exprUntil>");
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pos++;
        } else {
            erros.add("Erro:É esperado um until:" + tokens.get(pos).getLinha());
        }
    }

    private void pontoVirgula(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (tokens.get(pos).getToken().equals("Delimitador Ponto e Virgula")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<pontoVirgula>");
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pos++;
        } else {
            erros.add("Erro:É esperado um ; :" + tokens.get(pos).getLinha());
        }
    }

    private void doisPontos(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (tokens.get(pos).getToken().equals("Separador Dois Pontos")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getToken());
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pos++;
        } else {
            erros.add("Erro:É esperado um 'Dois Pontos' :" + tokens.get(pos).getLinha());
        }
        // pilhaDeNos.remove(pilhaDeNos.size() - 1);
    }

    private void abreParenteses(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (tokens.get(pos).getToken().equals("Delimitador Abre Parenteses")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<AbreParenteses>");
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pos++;
        } else {
            erros.add("Erro:É esperado um ( :" + tokens.get(pos).getLinha());
        }
    }

    private void fechaParenteses(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (tokens.get(pos).getToken().equals("Delimitador Fecha Parenteses")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<FechaParenteses>");
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pos++;
        } else {
            erros.add("Erro:É esperado um ) :" + tokens.get(pos).getLinha());
        }
    }

    private void fechaChaves(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (tokens.get(pos).getToken().equals("Delimitador Fecha Chaves")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<FechaChaves>");
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pos++;
        } else {
            erros.add("Erro:É esperado um ] :" + tokens.get(pos).getLinha());
        }
    }

    private void pontofinal(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (!tokens.get(pos).getToken().equals("Delimitador Ponto Final")) {
            erros.add("Erro:É esperado um ponto final :" + tokens.get(pos).getLinha());
        }else{
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
        }
    }

    private void doisPontosIgual(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (tokens.get(pos).getToken().equals("Operador Atribuição Dois Pontos Igual")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getToken());
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pos++;
        } else {
            erros.add("Erro:É esperado um dois pontos igual :" + tokens.get(pos).getLinha());
        }
    }

    private void program(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (tokens.get(pos).getToken().equals("Programa")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<program>");
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pos++;
        } else {
            erros.add("Erro:É esperado a palavra program:" + tokens.get(pos).getLinha());
        }
    }

    private void id(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (tokens.get(pos).getToken().equals("Identificador")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<id>");
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pos++;
        } else {
            erros.add("Erro:É esperado um identificador:" + tokens.get(pos).getLinha());
        }
    }

    private void programa(ArrayList<Token> tokens, ArrayList<String> erros) {
        program(tokens, erros);
        id(tokens, erros);
        pontoVirgula(tokens, erros);
        declaracoes(tokens, erros);
        bloco(tokens, erros);
        pontofinal(tokens, erros);

        for (int i = 0; i < raiz.getRowCount(); i++) {
            raiz.expandRow(i);
            raiz.setShowsRootHandles(true);
        }
    }

    private void bloco(ArrayList<Token> tokens, ArrayList<String> erros) {
        adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<bloco>");
        begin(tokens, erros);
        instrucoes(tokens, erros);
        end(tokens, erros);
        pilhaDeNos.remove(pilhaDeNos.size() - 1);
        // pilhaDeNos.remove(pilhaDeNos.size() - 1);
    }

    private void declaracoes(ArrayList<Token> tokens, ArrayList<String> erros) {
        adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<declaracoes>");
        declaracaoVariavel(tokens, erros);
        declaracaoConstante(tokens, erros);
        declProcedimento(tokens, erros);
        pilhaDeNos.remove(pilhaDeNos.size() - 1);
    }

    private void declaracaoConstante(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (tokens.get(pos).getToken().equals("Declaração Constante")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<declaracaoConstante>");
            pos++;
            declConsList(tokens, erros);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
        }

    }

    private void declConsList(ArrayList<Token> tokens, ArrayList<String> erros) {
        adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<declConsList>");
        declCons(tokens, erros);
        declConsList2(tokens, erros);
        pilhaDeNos.remove(pilhaDeNos.size() - 1);

    }

    private void declConsList2(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (tokens.get(pos).getToken().equals("Identificador")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<declCons>");
            declCons(tokens, erros);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            declConsList2(tokens, erros);
        }
    }

    private void declCons(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (tokens.get(pos).getToken().equals("Identificador")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<constante>");
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pos++;
            if (tokens.get(pos).getToken().equals("Separador Dois Pontos")) {
                adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getToken());
                adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
                pilhaDeNos.remove(pilhaDeNos.size() - 1);
                pilhaDeNos.remove(pilhaDeNos.size() - 1);
                pos++;
                tipo(tokens, erros);
                doisPontosIgual(tokens, erros);
                valor(tokens, erros);
                pontoVirgula(tokens, erros);
            } else {
                doisPontosIgual(tokens, erros);
                valor(tokens, erros);
                pontoVirgula(tokens, erros);
            }
            
        } else {
            erros.add("Erro:É esperado um identificador:" + tokens.get(pos).getLinha());
        }

    }

    private void declaracaoVariavel(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (tokens.get(pos).getToken().equals("Declaração Variável")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<declaracaoVariavel>");
            pos++;
            declVarList(tokens, erros);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
        }
    }

    private void declVarList(ArrayList<Token> tokens, ArrayList<String> erros) {
        adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<declVarList>");
        declVar(tokens, erros);
        declVarList2(tokens, erros);
        pilhaDeNos.remove(pilhaDeNos.size() - 1);
    }

    private void declVarList2(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (testaVariavel(tokens, erros)) {
            declVar(tokens, erros);
            declVarList2(tokens, erros);
        }
    }

    private void declVar(ArrayList<Token> tokens, ArrayList<String> erros) {
        adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<declVar>");
        variavel(tokens, erros);
        conjuntoIds(tokens, erros);
        doisPontos(tokens, erros);
        tipo(tokens, erros);
        pontoVirgula(tokens, erros);
        pilhaDeNos.remove(pilhaDeNos.size() - 1);
    }

    private void conjuntoIds(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (tokens.get(pos).getToken().equals("Separador Vírgula")) {
            pos++;
            variavel(tokens, erros);
            conjuntoIds(tokens, erros);
        }
    }

    private void tipo(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (tokens.get(pos).getToken().equals("Tipo Inteiro") || tokens.get(pos).getToken().equals("Tipo Real") || tokens.get(pos).getToken().equals("Tipo Char") || tokens.get(pos).getToken().equals("Tipo String")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<tipo>");
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pos++;
        } else {
            erros.add("Erro:É esperado uma declaraçao de tipo(int,real,char,string):" + tokens.get(pos).getLinha());
        }
    }

    private void valor(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (tokens.get(pos).getToken().equals("Tipo Literal")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<valor>");
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pos++;
        } else {
            unario(tokens, erros);
        }
    }

    private void declProcedimento(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (tokens.get(pos).getToken().equals("Declaração Funcao") || tokens.get(pos).getToken().equals("Declaração Procedimento")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<declProcedimento>");
            declProc(tokens, erros);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            declProcedimento(tokens, erros);

        }
    }

    private void declProc(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (tokens.get(pos).getToken().equals("Declaração Procedimento")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<declProc>");
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<procedimento>");
            pos++;
            id(tokens, erros);
            abreParenteses(tokens, erros);
            parametros(tokens, erros);
            fechaParenteses(tokens, erros);
            pontoVirgula(tokens, erros);
            declaracaoVariavel(tokens, erros);
            bloco(tokens, erros);
            pontoVirgula(tokens, erros);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
        } else if (tokens.get(pos).getToken().equals("Declaração Funcao")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<declProc>");
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<funcão>");
            pos++;
            id(tokens, erros);
            abreParenteses(tokens, erros);
            parametros(tokens, erros);
            fechaParenteses(tokens, erros);
            doisPontos(tokens, erros);
            tipo(tokens, erros);
            pontoVirgula(tokens, erros);
            declaracaoVariavel(tokens, erros);
            bloco(tokens, erros);
            pontoVirgula(tokens, erros);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
        } else {
            erros.add("Erro:É esperado uma declaraçao de procedimento ou funçao:" + tokens.get(pos).getLinha());
        }
        //  pilhaDeNos.remove(pilhaDeNos.size() - 1);
    }

    private void parametros(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (tokens.get(pos).getToken().equals("Identificador")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<parametros>");
            declVarList(tokens, erros);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
        }

    }

    private void instrucoes(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (tokens.get(pos).getToken().equals("Identificador") || tokens.get(pos).getToken().equals("Instrução If") || tokens.get(pos).getToken().equals("For") || tokens.get(pos).getToken().equals("Instrução While") || tokens.get(pos).getToken().equals("Instrução Repeat") || tokens.get(pos).getToken().equals("Instrução Break") || tokens.get(pos).getToken().equals("Instrução Continue") || tokens.get(pos).getToken().equals("Instrução Delimitador Inicio(begin)")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<instrucoes>");
            inst(tokens, erros);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            instrucoes(tokens, erros);

        }
    }
    boolean laco=false;
    private void inst(ArrayList<Token> tokens, ArrayList<String> erros) {

        adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<inst>");        
        if (tokens.get(pos).getToken().equals("For")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<" + tokens.get(pos).getToken() + ">");
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
            pilhaDeNos.remove(pilhaDeNos.size() - 1);            
            pos++;
            laco=true;
            variavel(tokens, erros);
            doisPontosIgual(tokens, erros);
            fator(tokens, erros);
            exprto(tokens, erros);
            fator(tokens, erros);
            exprdo(tokens, erros);
            inst(tokens, erros);
            laco=false;
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
        } else if (tokens.get(pos).getToken().equals("Identificador")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<Identificador>");
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
            pilhaDeNos.remove(pilhaDeNos.size() - 1);     
            pos++;
            expressao(tokens, erros);
            pontoVirgula(tokens, erros);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
        } else if (tokens.get(pos).getToken().equals("Instrução If")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<" + tokens.get(pos).getToken() + ">");
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pos++;
            expr(tokens, erros);
            exprthen(tokens, erros);
            inst(tokens, erros);
            stmtIf(tokens, erros);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
        } else if (tokens.get(pos).getToken().equals("Instrução While")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<" + tokens.get(pos).getToken() + ">");
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            laco = true;
            pos++;
            expr(tokens, erros);
            exprdo(tokens, erros);
            inst(tokens, erros);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            laco = false;
        } else if (tokens.get(pos).getToken().equals("Instrução Repeat")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<" + tokens.get(pos).getToken() + ">");
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            laco = true;
            pos++;
            inst(tokens, erros);
            expruntil(tokens, erros);
            expr(tokens, erros);
            pontoVirgula(tokens, erros);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            laco = false;
        } else if (tokens.get(pos).getToken().equals("Instrução Break")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<" + tokens.get(pos).getToken() + ">");
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pos++;
            pontoVirgula(tokens, erros);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            if(!laco) erros.add("Erro:Break declarado fora de um laço: " + tokens.get(pos).getLinha());
        } else if (tokens.get(pos).getToken().equals("Instrução Continue")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<" + tokens.get(pos).getToken() + ">");
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pos++;
            pontoVirgula(tokens, erros);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            if(!laco) erros.add("Erro:Continue declarado fora de um laço: " + tokens.get(pos).getLinha());
        } else if (tokens.get(pos).getToken().equals("Delimitador Inicio(begin)")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<" + tokens.get(pos).getToken() + ">");
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            bloco(tokens, erros);
            pontoVirgula(tokens, erros);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
        } else {
            erros.add("Erro:É esperado uma instrução: " + tokens.get(pos).getLinha());
        }
        pilhaDeNos.remove(pilhaDeNos.size() - 1);
    }

    private void stmtIf(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (tokens.get(pos).getToken().equals("Instrução Else")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<stmtIf>");
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<" + tokens.get(pos).getToken() + ">");
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pos++;
            inst(tokens, erros);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
        }
    }

    private void expressao(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (tokens.get(pos).getToken().equals("Operador Atribuição Dois Pontos Igual") || tokens.get(pos).getToken().equals("Delimitador Abre Parenteses") || tokens.get(pos).getLexema().toLowerCase().equals("[")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<expressao>");
            if (tokens.get(pos).getToken().equals("Operador Atribuição Dois Pontos Igual")) {
                adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<" + tokens.get(pos).getToken() + ">");
                adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
                pilhaDeNos.remove(pilhaDeNos.size() - 1);
                pos++;
                expr(tokens, erros);
                pilhaDeNos.remove(pilhaDeNos.size() - 1);
            } else if (tokens.get(pos).getToken().equals("Delimitador Abre Chaves")) {
                adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<" + tokens.get(pos).getToken() + ">");
                adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
                pilhaDeNos.remove(pilhaDeNos.size() - 1);
                pos++;
                expr(tokens, erros);
                fechaChaves(tokens, erros);
                exprdoispontosigual(tokens, erros);
                expr(tokens, erros);
                pilhaDeNos.remove(pilhaDeNos.size() - 1);
            } else if (tokens.get(pos).getToken().equals("Delimitador Abre Parenteses")) {
                adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<" + tokens.get(pos).getToken() + ">");
                adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
                pilhaDeNos.remove(pilhaDeNos.size() - 1);
                pos++;
                parametros2(tokens, erros);
                fechaParenteses(tokens, erros);
                pilhaDeNos.remove(pilhaDeNos.size() - 1);
            }
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
        } else {
            erros.add("Erro:É esperado uma expressao:" + tokens.get(pos).getLinha());
        }
    }

    private void parametros2(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (tokens.get(pos).getToken().equals("Operador Aritmético Adição") || tokens.get(pos).getToken().equals("Operador Aritmético Subtração") || tokens.get(pos).getToken().equals("Delimitador Abre Parenteses") || tokens.get(pos).getToken().equals("Identificador") || tokens.get(pos).getToken().equals("Tipo Literal") || tokens.get(pos).getToken().equals("Tipo Num")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<" + tokens.get(pos).getToken() + ">");
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            expr(tokens, erros);
            parametros3(tokens, erros);
        }
    }

    private void parametros3(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (tokens.get(pos).getToken().equals("Separador Vírgula")) {
            pos++;
            expr(tokens, erros);
            parametros3(tokens, erros);
        }
    }

    private void expr(ArrayList<Token> tokens, ArrayList<String> erros) {
        adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<expr>");
        exprComparacao(tokens, erros);
        expr2(tokens, erros);
        pilhaDeNos.remove(pilhaDeNos.size() - 1);
    }

    private void expr2(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (tokens.get(pos).getToken().equals("Operador Lógico OU") || tokens.get(pos).getToken().equals("Operador Lógico E")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<" + tokens.get(pos).getToken() + ">");
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pos++;
            exprComparacao(tokens, erros);
            expr2(tokens, erros);
        }
    }

    private void exprComparacao(ArrayList<Token> tokens, ArrayList<String> erros) {
        adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<exprComparação>");
        exprOp(tokens, erros);
        exprComparacao2(tokens, erros);
        pilhaDeNos.remove(pilhaDeNos.size() - 1);
    }

    private void exprComparacao2(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (tokens.get(pos).getToken().equals("Operador Comparação Igual") || tokens.get(pos).getToken().equals("Operador Comparação Diferente") || tokens.get(pos).getToken().equals("Operador Comparação Menor") || tokens.get(pos).getToken().equals("Operador Comparação Menor Igual") || tokens.get(pos).getToken().equals("Operador Comparação Maior") || tokens.get(pos).getToken().equals("Operador Comparação Maior Igual")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<" + tokens.get(pos).getToken() + ">");
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pos++;
            exprOp(tokens, erros);
            exprComparacao2(tokens, erros);
        }
    }

    private void exprOp(ArrayList<Token> tokens, ArrayList<String> erros) {
        adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<exprOp>");
        termo(tokens, erros);
        exprOp2(tokens, erros);
        pilhaDeNos.remove(pilhaDeNos.size() - 1);
    }

    private void exprOp2(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (tokens.get(pos).getToken().equals("Operador Aritmético Adição") || tokens.get(pos).getToken().equals("Operador Aritmético Subtração")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<" + tokens.get(pos).getToken() + ">");
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pos++;
            termo(tokens, erros);
            exprOp2(tokens, erros);
        }
    }

    private void termo(ArrayList<Token> tokens, ArrayList<String> erros) {
        adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<termo>");
        unario(tokens, erros);
        termo2(tokens, erros);
        pilhaDeNos.remove(pilhaDeNos.size() - 1);
    }

    private void termo2(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (tokens.get(pos).getToken().equals("Operador Aritmético Multiplicação") || tokens.get(pos).getToken().equals("Operador Aritmético Divisão")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getToken());
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pos++;
            unario(tokens, erros);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            termo2(tokens, erros);
            
        }
    }

    private void unario(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (tokens.get(pos).getToken().equals("Operador Aritmético Adição") || tokens.get(pos).getToken().equals("Operador Aritmético Subtração")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<unario>");
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pos++;
        }
        fator(tokens, erros);
    }

    private void fator(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (tokens.get(pos).getToken().equals("Delimitador Abre Parenteses")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getToken());
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pos++;
            expr(tokens, erros);
            if (tokens.get(pos).getToken().equals("Delimitador Fecha Parenteses")) {
                adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getToken());
                adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
                pilhaDeNos.remove(pilhaDeNos.size() - 1);
                pilhaDeNos.remove(pilhaDeNos.size() - 1);
                pos++;
            } else {
                erros.add("Erro:É esperado um ) :" + tokens.get(pos).getLinha());
            }
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
        } else if (testaVariavel(tokens, erros)) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getToken());
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pos++;
        } else if (tokens.get(pos).getToken().equals("Tipo Num") || tokens.get(pos).getToken().equals("Tipo Literal")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getToken());
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pos++;
        } else {
            erros.add("Erro:É esperado um fator:" + tokens.get(pos).getLinha());
        }

    }

    private void variavel(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (tokens.get(pos).getToken().equals("Identificador")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<variavel>");
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pos++;
            variavel2(tokens, erros);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
        } else {
            erros.add("Erro:É esperado um identificador:" + tokens.get(pos).getLinha());
        }

    }

    private void variavel2(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (tokens.get(pos).getLexema().toLowerCase().equals("[")) {
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "<variavel2>");
            adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
            pos++;
            exprOp(tokens, erros);
            exprfechachaves(tokens, erros);
            pilhaDeNos.remove(pilhaDeNos.size() - 1);
        }
    }

    private boolean testaVariavel(ArrayList<Token> tokens, ArrayList<String> erros) {
        if (tokens.get(pos).getToken().equals("Identificador")) {
            return true;
        } else {
            return false;
        }
    }

    public void inicio(ArrayList<Token> tokens, ArrayList<String> erros) {
        pos = 0;
        programa(tokens, erros);

    }

//------------------------------------------------------------------------------------------------
/*    private void begin(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (tokens.get(pos).getToken().equals("Delimitador Inicio(begin)")) {
     pos++;
     } else {
     erros.add("Erro:É esperado begin:" + tokens.get(pos).getLinha());
     }
     }

     private void end(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (tokens.get(pos).getToken().equals("Delimitador Fim")) {
     pos++;
     } else {
     erros.add("Erro:É esperado end:" + tokens.get(pos).getLinha());
     }
     }

     private void exprfechachaves(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (tokens.get(pos).getLexema().equals("]")) {
     pos++;
     } else {
     erros.add("Erro:É esperado um ]:" + tokens.get(pos).getLinha());
     }
     }

     private void exprdoispontosigual(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (tokens.get(pos).getToken().equals("Operador Atribuição Dois Pontos Igual")) {
     pos++;
     } else {
     erros.add("Erro:É esperado um dois pontos igual:" + tokens.get(pos).getLinha());
     }
     }

     private void exprthen(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (tokens.get(pos).getToken().equals("Instrução Then")) {
     pos++;
     } else {
     erros.add("Erro:É esperado um then:" + tokens.get(pos).getLinha());
     }
     }

     private void exprdo(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (tokens.get(pos).getToken().equals("Instrução Do")) {
     pos++;
     } else {
     erros.add("Erro:É esperado um do:" + tokens.get(pos).getLinha());
     }
     }

     private void expruntil(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (tokens.get(pos).getToken().equals("Instrução Until")) {
     pos++;
     } else {
     erros.add("Erro:É esperado um until:" + tokens.get(pos).getLinha());
     }
     }

     private void pontoVirgula(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (tokens.get(pos).getToken().equals("Delimitador Ponto e Virgula")) {
     adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "Ponto e virgula");
     pilhaDeNos.remove(pilhaDeNos.size() - 1);
     pos++;
     } else {
     erros.add("Erro:É esperado um ; :" + tokens.get(pos).getLinha());
     }
     }

     private void doisPontos(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (!tokens.get(pos).getToken().equals("Separador Dois Pontos")) {
     adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "doisPontos");
     pilhaDeNos.remove(pilhaDeNos.size() - 1);
     erros.add("Erro:É esperado um 'Dois Pontos' :" + tokens.get(pos).getLinha());
     } else {
     pos++;
     }
     }

     private void abreParenteses(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (tokens.get(pos).getToken().equals("Delimitador Abre Parenteses")) {
     pos++;
     } else {
     erros.add("Erro:É esperado um ( :" + tokens.get(pos).getLinha());
     }
     }

     private void fechaParenteses(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (tokens.get(pos).getToken().equals("Delimitador Fecha Parenteses")) {
     pos++;
     } else {
     erros.add("Erro:É esperado um ) :" + tokens.get(pos).getLinha());
     }
     }

     private void fechaChaves(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (tokens.get(pos).getToken().equals("Delimitador Fecha Chaves")) {
     pos++;
     } else {
     erros.add("Erro:É esperado um ] :" + tokens.get(pos).getLinha());
     }
     }

     private void pontofinal(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (!tokens.get(pos).getToken().equals("Delimitador Ponto Final")) {
     erros.add("Erro:É esperado um ponto final :" + tokens.get(pos).getLinha());
     }
     }

     private void doisPontosIgual(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (tokens.get(pos).getToken().equals("Operador Atribuição Dois Pontos Igual")) {
     adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "doisPontosIgual");
     pilhaDeNos.remove(pilhaDeNos.size() - 1);
     pos++;
     } else {
     erros.add("Erro:É esperado um dois pontos igual :" + tokens.get(pos).getLinha());
     }
     }

     private void program(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (!tokens.get(pos).getToken().equals("Programa")) {
     erros.add("Erro:É esperado a palavra program:" + tokens.get(pos).getLinha());
     } else {
     adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "Program");
     adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
     pilhaDeNos.remove(pilhaDeNos.size() - 1);
     pos++;
     }
     }

     private void id(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (!tokens.get(pos).getToken().equals("Identificador")) {
     erros.add("Erro:É esperado um identificador:" + tokens.get(pos).getLinha());
     } else {
     adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "Identificador");
     pilhaDeNos.remove(pilhaDeNos.size() - 1);
     pos++;
     }
     }

     private void programa(ArrayList<Token> tokens, ArrayList<String> erros) {
     program(tokens, erros);
     id(tokens, erros);
     pontoVirgula(tokens, erros);
     declaracoes(tokens, erros);
     bloco(tokens, erros);
     pontofinal(tokens, erros);
     }

     private void bloco(ArrayList<Token> tokens, ArrayList<String> erros) {
     begin(tokens, erros);
     instrucoes(tokens, erros);
     end(tokens, erros);
     }

     private void declaracoes(ArrayList<Token> tokens, ArrayList<String> erros) {
     declaracaoVariavel(tokens, erros);
     declaracaoConstante(tokens, erros);
     declProcedimento(tokens, erros);
     }

     private void declaracaoConstante(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (tokens.get(pos).getToken().equals("Declaração Constante")) {
     adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "declaracaoConstante");
     pos++;
     declConsList(tokens, erros);
     pilhaDeNos.remove(pilhaDeNos.size() - 1);
     }
     }

     private void declConsList(ArrayList<Token> tokens, ArrayList<String> erros) {
     declCons(tokens, erros);
     declConsList2(tokens, erros);
     }

     private void declConsList2(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (tokens.get(pos).getToken().equals("Identificador")) {
     declCons(tokens, erros);
     declConsList2(tokens, erros);
     }
     }

     private void declCons(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (tokens.get(pos).getToken().equals("Identificador")) {
     adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "Identificador");
     adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
     pilhaDeNos.remove(pilhaDeNos.size() - 1);
            
     pos++;
     if (tokens.get(pos).getToken().equals("Separador Dois Pontos")) {
     pilhaDeNos.remove(pilhaDeNos.size() - 1);
     adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "Separador Dois Pontos");
     pos++;
     tipo(tokens, erros);
     doisPontosIgual(tokens, erros);
     valor(tokens, erros);
     pontoVirgula(tokens, erros);
     pilhaDeNos.remove(pilhaDeNos.size() - 1);
     } else {
     pilhaDeNos.remove(pilhaDeNos.size() - 1);
     doisPontosIgual(tokens, erros);
     valor(tokens, erros);
     pontoVirgula(tokens, erros);
     // pilhaDeNos.remove(pilhaDeNos.size() - 1);
     }
     } else {
     erros.add("Erro:É esperado um identificador:" + tokens.get(pos).getLinha());
     }
     }

     private void declaracaoVariavel(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (tokens.get(pos).getToken().equals("Declaração Variável")) {
     adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "declaracaoVariavel");
     pos++;
     declVarList(tokens, erros);
     pilhaDeNos.remove(pilhaDeNos.size() - 1);
     }
     }

     private void declVarList(ArrayList<Token> tokens, ArrayList<String> erros) {
     declVar(tokens, erros);
     declVarList2(tokens, erros);
     }

     private void declVarList2(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (testaVariavel(tokens, erros)) {
     declVar(tokens, erros);
     declVarList2(tokens, erros);
     }
     }

     private void declVar(ArrayList<Token> tokens, ArrayList<String> erros) {
     variavel(tokens, erros);
     conjuntoIds(tokens, erros);
     doisPontos(tokens, erros);
     tipo(tokens, erros);
     pontoVirgula(tokens, erros);
     }

     private void conjuntoIds(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (tokens.get(pos).getToken().equals("Separador Vírgula")) {
     pos++;
     pilhaDeNos.remove(pilhaDeNos.size() - 1);
     variavel(tokens, erros);
     conjuntoIds(tokens, erros);
     }
     }

     private void tipo(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (tokens.get(pos).getToken().equals("Tipo Inteiro") || tokens.get(pos).getToken().equals("Tipo Real") || tokens.get(pos).getToken().equals("Tipo Char") || tokens.get(pos).getToken().equals("Tipo String")) {
     pilhaDeNos.remove(pilhaDeNos.size() - 1);
     adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "tipo");
     adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getToken());
     pilhaDeNos.remove(pilhaDeNos.size() - 1);
     pilhaDeNos.remove(pilhaDeNos.size() - 1);
     pos++;
     } else {
     erros.add("Erro:É esperado uma declaraçao de tipo(int,real,char,string):" + tokens.get(pos).getLinha());
     }
     }

     private void valor(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (tokens.get(pos).getToken().equals("Tipo Literal")) {
     adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "valor");
     adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
     pilhaDeNos.remove(pilhaDeNos.size() - 1);
     pos++;
     } else {
     unario(tokens, erros);
     }
     }

     private void declProcedimento(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (tokens.get(pos).getToken().equals("Declaração Funcao") || tokens.get(pos).getToken().equals("Declaração Procedimento")) {
     declProc(tokens, erros);
     declProcedimento(tokens, erros);
     }
     }

     private void declProc(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (tokens.get(pos).getToken().equals("Declaração Procedimento")) {
     pos++;
     id(tokens, erros);
     abreParenteses(tokens, erros);
     parametros(tokens, erros);
     fechaParenteses(tokens, erros);
     pontoVirgula(tokens, erros);
     declaracaoVariavel(tokens, erros);
     bloco(tokens, erros);
     pontoVirgula(tokens, erros);
     } else if (tokens.get(pos).getToken().equals("Declaração Funcao")) {
     pos++;
     id(tokens, erros);
     abreParenteses(tokens, erros);
     parametros(tokens, erros);
     fechaParenteses(tokens, erros);
     doisPontos(tokens, erros);
     tipo(tokens, erros);
     pontoVirgula(tokens, erros);
     declaracaoVariavel(tokens, erros);
     bloco(tokens, erros);
     pontoVirgula(tokens, erros);
     } else {
     erros.add("Erro:É esperado uma declaraçao de procedimento ou funçao:" + tokens.get(pos).getLinha());
     }

     }

     private void parametros(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (tokens.get(pos).getToken().equals("Identificador")) {
     declVarList(tokens, erros);
     }
     }

     private void instrucoes(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (tokens.get(pos).getToken().equals("Identificador") || tokens.get(pos).getToken().equals("Instrução If") || tokens.get(pos).getToken().equals("Instrução While") || tokens.get(pos).getToken().equals("Instrução Repeat") || tokens.get(pos).getToken().equals("Instrução Break") || tokens.get(pos).getToken().equals("Instrução Continue") || tokens.get(pos).getToken().equals("Instrução Delimitador Inicio(begin)")) {

     inst(tokens, erros);
     instrucoes(tokens, erros);
     }
     }

     private void inst(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (tokens.get(pos).getToken().equals("Identificador")) {
     pos++;

     expressao(tokens, erros);
     pontoVirgula(tokens, erros);
     } else if (tokens.get(pos).getToken().equals("Instrução If")) {
     pos++;
     expr(tokens, erros);
     exprthen(tokens, erros);
     inst(tokens, erros);
     stmtIf(tokens, erros);
     } else if (tokens.get(pos).getToken().equals("Instrução While")) {
     pos++;
     expr(tokens, erros);
     exprdo(tokens, erros);
     inst(tokens, erros);
     } else if (tokens.get(pos).getToken().equals("Instrução Repeat")) {
     pos++;
     inst(tokens, erros);
     expruntil(tokens, erros);
     expr(tokens, erros);
     pontoVirgula(tokens, erros);
     } else if (tokens.get(pos).getToken().equals("Instrução Break")) {
     pos++;
     pontoVirgula(tokens, erros);
     } else if (tokens.get(pos).getToken().equals("Instrução Continue")) {
     pos++;
     pontoVirgula(tokens, erros);
     } else if (tokens.get(pos).getToken().equals("Delimitador Inicio(begin)")) {
     bloco(tokens, erros);
     pontoVirgula(tokens, erros);
     } else {
     erros.add("Erro:É esperado uma instrução: " + tokens.get(pos).getLinha());
     }
     }

     private void stmtIf(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (tokens.get(pos).getToken().equals("Instrução Else")) {
     pos++;
     inst(tokens, erros);
     }
     }

     private void expressao(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (tokens.get(pos).getToken().equals("Operador Atribuição Dois Pontos Igual") || tokens.get(pos).getToken().equals("Delimitador Abre Parenteses") || tokens.get(pos).getLexema().toLowerCase().equals("[")) {
     if (tokens.get(pos).getToken().equals("Operador Atribuição Dois Pontos Igual")) {
     pos++;
     expr(tokens, erros);
     } else if (tokens.get(pos).getToken().equals("Delimitador Abre Chaves")) {
     pos++;
     expr(tokens, erros);
     fechaChaves(tokens, erros);
     exprdoispontosigual(tokens, erros);
     expr(tokens, erros);
     } else if (tokens.get(pos).getToken().equals("Delimitador Abre Parenteses")) {
     pos++;
     parametros2(tokens, erros);
     fechaParenteses(tokens, erros);
     }
     } else {
     erros.add("Erro:É esperado uma expressao:" + tokens.get(pos).getLinha());
     }
     }

     private void parametros2(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (tokens.get(pos).getToken().equals("Operador Aritmético Adição") || tokens.get(pos).getToken().equals("Operador Aritmético Subtração") || tokens.get(pos).getToken().equals("Delimitador Abre Parenteses") || tokens.get(pos).getToken().equals("Identificador") || tokens.get(pos).getToken().equals("Tipo Literal") || tokens.get(pos).getToken().equals("Tipo Num")) {
     expr(tokens, erros);
     parametros3(tokens, erros);
     }
     }

     private void parametros3(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (tokens.get(pos).getToken().equals("Separador Vírgula")) {
     pos++;
     expr(tokens, erros);
     parametros3(tokens, erros);
     }
     }

     private void expr(ArrayList<Token> tokens, ArrayList<String> erros) {

     exprComparacao(tokens, erros);
     expr2(tokens, erros);
     }

     private void expr2(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (tokens.get(pos).getToken().equals("Operador Lógico OU") || tokens.get(pos).getToken().equals("Operador Lógico E")) {
     pos++;
     exprComparacao(tokens, erros);
     expr2(tokens, erros);
     }
     }

     private void exprComparacao(ArrayList<Token> tokens, ArrayList<String> erros) {

     exprOp(tokens, erros);
     exprComparacao2(tokens, erros);
     }

     private void exprComparacao2(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (tokens.get(pos).getToken().equals("Operador Comparação Igual") || tokens.get(pos).getToken().equals("Operador Comparação Diferente") || tokens.get(pos).getToken().equals("Operador Comparação Menor") || tokens.get(pos).getToken().equals("Operador Comparação Menor Igual") || tokens.get(pos).getToken().equals("Operador Comparação Maior") || tokens.get(pos).getToken().equals("Operador Comparação Maior Igual")) {
     pos++;
     exprOp(tokens, erros);
     exprComparacao2(tokens, erros);
     }
     }

     private void exprOp(ArrayList<Token> tokens, ArrayList<String> erros) {

     termo(tokens, erros);
     exprOp2(tokens, erros);
     }

     private void exprOp2(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (tokens.get(pos).getToken().equals("Operador Aritmético Adição") || tokens.get(pos).getToken().equals("Operador Aritmético Subtração")) {
     pos++;
     termo(tokens, erros);
     exprOp2(tokens, erros);
     }
     }

     private void termo(ArrayList<Token> tokens, ArrayList<String> erros) {

     unario(tokens, erros);
     termo2(tokens, erros);
     }

     private void termo2(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (tokens.get(pos).getToken().equals("Operador Aritmético Multiplicação") || tokens.get(pos).getToken().equals("Operador Aritmético Divisão")) {
     pos++;
     unario(tokens, erros);
     termo2(tokens, erros);
     }
     }

     private void unario(ArrayList<Token> tokens, ArrayList<String> erros) {

     if (tokens.get(pos).getToken().equals("Operador Aritmético Adição") || tokens.get(pos).getToken().equals("Operador Aritmético Subtração")) {
     adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
     pilhaDeNos.remove(pilhaDeNos.size() - 1);
     pos++;
     }
     fator(tokens, erros);
     }

     private void fator(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (tokens.get(pos).getToken().equals("Delimitador Abre Parenteses")) {
     adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
     pilhaDeNos.remove(pilhaDeNos.size() - 1);
     pos++;
     expr(tokens, erros);
     if (tokens.get(pos).getToken().equals("Delimitador Fecha Parenteses")) {
     adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
     pilhaDeNos.remove(pilhaDeNos.size() - 1);
     pos++;
     } else {
     erros.add("Erro:É esperado um ) :" + tokens.get(pos).getLinha());
     }
     } else if (testaVariavel(tokens, erros)) {
     pos++;
     } else if (tokens.get(pos).getToken().equals("Tipo Num") || tokens.get(pos).getToken().equals("Tipo Literal")) {
     adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
     pilhaDeNos.remove(pilhaDeNos.size() - 1);
     pos++;
     } else {
     erros.add("Erro:É esperado um fator:" + tokens.get(pos).getLinha());
     }

     }

     private void variavel(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (tokens.get(pos).getToken().equals("Identificador")) {
     adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "Identificador");
     adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), tokens.get(pos).getLexema());
     pilhaDeNos.remove(pilhaDeNos.size() - 1);
     pos++;
     variavel2(tokens, erros);
     } else {
     erros.add("Erro:É esperado um identificador:" + tokens.get(pos).getLinha());
     }
     }

     private void variavel2(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (tokens.get(pos).getLexema().toLowerCase().equals("[")) {
     adicionarNo(pilhaDeNos.get(pilhaDeNos.size() - 1), "variavel2");
     pos++;
     exprOp(tokens, erros);
     exprfechachaves(tokens, erros);
     }
     }

     private boolean testaVariavel(ArrayList<Token> tokens, ArrayList<String> erros) {
     if (tokens.get(pos).getToken().equals("Identificador")) {
     return true;
     } else {
     return false;
     }
     }

     public void inicio(ArrayList<Token> tokens, ArrayList<String> erros) {
     pos = 0;
     programa(tokens, erros);

     }
     */
}
